#include <qapplication.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpixmap.h>
#include <qcursor.h>
#include <qlistview.h>
#include <qheader.h>
#include <qpainter.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qsettings.h>


#include "Label.h"

#include <gloox/client.h>
#include <gloox/messagehandler.h>
#include <gloox/connectionlistener.h>
#include <gloox/rostermanager.h>
#include <qthread.h>
#include <qtimer.h>

#include "UserSettings.h"
#include "LoginWidget.h"

class InnerWidget
	: public QWidget
{
	//Q_OBJECT
public:
	InnerWidget(QWidget * parent = 0, const char * name = 0)
		: QWidget(parent, name)
	{
		QColor bgColor(146, 179, 232);
		setPaletteBackgroundColor(bgColor);

		QHBoxLayout * pHBoxLayout = new QHBoxLayout(this);
		pHBoxLayout->setMargin(6);
		pHBoxLayout->setSpacing(7);

		QLabel * pLabelChat = new QLabel(this);
		pLabelChat->setPixmap(QPixmap::fromMimeSource(QString("chat.png")));
		pLabelChat->setCursor(Qt::PointingHandCursor);
		pHBoxLayout->addWidget(pLabelChat);

		QLabel * pLabelCall = new QLabel(this);
		pLabelCall->setPixmap(QPixmap::fromMimeSource(QString("call.png")));
		pLabelCall->setCursor(Qt::PointingHandCursor);
		pHBoxLayout->addWidget(pLabelCall);

		QLabel * pLabelVoiceMail = new QLabel(this);
		pLabelVoiceMail->setPixmap(QPixmap::fromMimeSource(QString("send_voicemail.png")));
		pLabelVoiceMail->setCursor(Qt::PointingHandCursor);
		pHBoxLayout->addWidget(pLabelVoiceMail);

		pHBoxLayout->addStretch();

		QLabel * pLabelMenu = new QLabel(this);
		pLabelMenu->setPixmap(QPixmap::fromMimeSource(QString("menu.png")));
		pLabelMenu->setCursor(Qt::PointingHandCursor);
		pHBoxLayout->addWidget(pLabelMenu);
	}

	~InnerWidget()	
	{
		qDebug("~InnerWidget");
	}
};

class DownWidget
	: public QWidget
{
	Q_OBJECT

public:
	DownWidget(QWidget * parent = 0, const char * name = 0)
		: QWidget(parent, name)
	{
		QColor bgColor(Qt::white);
		setPaletteBackgroundColor(bgColor);

		QVBoxLayout * pVBoxLayout = new QVBoxLayout(this);
		pVBoxLayout->setMargin(6);
		pVBoxLayout->setSpacing(4);

		QHBoxLayout * pHBoxLayout = new QHBoxLayout;
		pHBoxLayout->addStretch();

		QLabel * pLabelPhoto = new QLabel(this);
		pLabelPhoto->setPixmap(QPixmap::fromMimeSource("photo.png"));
		pHBoxLayout->addWidget(pLabelPhoto);


		pVBoxLayout->addLayout(pHBoxLayout);

		pVBoxLayout->addStretch();

		QFrame * pFrame = new QFrame(this);
		pFrame->setPaletteForegroundColor(QColor(162, 162, 162));
		pFrame->setFrameShape(QFrame::HLine);
		pVBoxLayout->addWidget(pFrame);

		pUrlLabelJid = new UrlLabel(this);
		pUrlLabelJid->setPaletteBackgroundColor(bgColor);
		pUrlLabelJid->setBackgroundOrigin(QLabel::ParentOrigin);
		pUrlLabelJid->setText(tr("your@email.here"));
		QFont font("Arial", 9);
		pUrlLabelJid->setFont(font);
		pVBoxLayout->addWidget(pUrlLabelJid);
	}

	~DownWidget()	
	{
		qDebug("~DownWidget");
	}

	UrlLabel * pUrlLabelJid;
};



class MyWidget
	: public QWidget
{
	Q_OBJECT
	
	QTimer * timerHide;
public:
	MyWidget(QWidget * parent = 0, const char * name = 0)
		: QWidget(parent, name, (Qt::WStyle_Customize | WStyle_NoBorder | WStyle_Tool))
	{
		setPaletteBackgroundColor(QColor(128, 128, 128));
		QVBoxLayout * pVBoxLayout = new QVBoxLayout(this);
		pVBoxLayout->setMargin(1);

		pInnerWidget = new InnerWidget(this);
		pVBoxLayout->addWidget(pInnerWidget);		

		pDownWidget = new DownWidget(this);
		pVBoxLayout->addWidget(pDownWidget);
		
		timerHide = new QTimer(this);
		connect(timerHide, SIGNAL(timeout()), SLOT(hide_time()));
	}

	~MyWidget()	
	{
		qDebug("~MyWidget");
	}

	InnerWidget * pInnerWidget;
	DownWidget * pDownWidget;
	
	void enterEvent(QEvent *)
	{
	    timerHide->stop();
	}
	
	void leaveEvent(QEvent *)
	{
	    hide();
	}

	void show()
	{
		timerHide->stop();
		QWidget::show();
	}
	
	void hide()
	{
	    timerHide->start(100, TRUE);
	}
	
public slots:	
	void hide_time()
	{
	    QWidget::hide();	    
	}
};

class MyListView
	: public QListView
{
	MyWidget * pMyWidget;

public:
	MyListView(QWidget * parent = 0, const char * name = 0)
		: QListView(parent, name)
	{
		setPaletteBackgroundColor(parent ? parent->paletteBackgroundColor() : Qt::white);

		setAllColumnsShowFocus(true);
		setTreeStepSize(0);
		setSorting(0, false);
		setResizeMode(QListView::LastColumn);
		setFrameShape(QFrame::NoFrame);

		addColumn("");
		header()->hide();

		pMyWidget = new MyWidget;
		pMyWidget->hide();
	}

	~MyListView()
	{
		qDebug("~MyListView");
		delete pMyWidget;
	}


protected:
	void contentsMouseMoveEvent(QMouseEvent* e)
	{
		QListViewItem * item = itemAt(e->pos());
		if (item == 0)
		{
			setSelected(selectedItem(), FALSE);
			pMyWidget->hide();
			setCursor(Qt::ArrowCursor);
		}
		else
		{
			setSelected(item, TRUE);
			pMyWidget->show();
			setCursor(Qt::PointingHandCursor);
			pMyWidget->pDownWidget->pUrlLabelJid->setText(item->text(0));

			QPoint point = mapToGlobal(QPoint(header()->sectionPos(0), itemPos(item)));
			pMyWidget->move(
			    point.x() < (QApplication::desktop()->width() - pMyWidget->width()) / 2 ? point.x() + width() : point.x() - pMyWidget->width(),
			    QMIN(point.y(), QApplication::desktop()->height() - pMyWidget->height()));
		}
	}

	void leaveEvent(QEvent *)
	{
		setSelected(selectedItem(), FALSE);
		pMyWidget->hide();
	}

};

class MyListViewItem
	: public QListViewItem
{
public:
	MyListViewItem(QListView * parent)
		: QListViewItem(parent)
	{
		setText(0, QString("some text %1").arg(rand() % 100));
		setPixmap(0, QPixmap("status.png"));
	}

	~MyListViewItem()
	{
		qDebug("~MyListViewItem");
	}

	void paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int alignment)
	{
		if (isSelected())
		{
			QColorGroup grp(cg);
			grp.setColor(QColorGroup::Highlight, QColor(214, 217, 229));
			grp.setColor(QColorGroup::HighlightedText, grp.text());
	        QListViewItem::paintCell(p, grp, column, width, alignment);
		}
		else
		{
	        QListViewItem::paintCell(p, cg, column, width, alignment);
			p->setPen(QColor(240, 240, 240));
			p->drawLine(0, height() - 1, width, height() - 1);
		}
	}

	void paintFocus(QPainter *, const QColorGroup &, const QRect &) {}
	void paintBranches(QPainter *, const QColorGroup &, int, int, int) {}
};

class MainWidget
	: public QWidget
	, public QThread
	, public gloox::MessageHandler
	, public gloox::ConnectionListener
	, public gloox::RosterListener
	, public gloox::UserSettingHandler
{
	Q_OBJECT

	gloox::Client * pClient;
	QSettings m_settings;

public:
	MainWidget(QWidget * parent = 0, const char * name = "MainWidget")
		: QWidget(parent, name)
	{
		m_settings.setPath("Vinnitu Ltd.", "QTalk");

		setPaletteBackgroundColor(Qt::white);
		pLoginWidget = new LoginWidget(this);
		pLoginWidget->setUsername(m_settings.readEntry("/username", ""));
		bool bRemember = m_settings.readBoolEntry("/remember", true);
		pLoginWidget->setRemember(bRemember);
		if (bRemember)
			pLoginWidget->setPassword(m_settings.readEntry("/password", ""));

		QFont font("Arial", 9);
		setFont(font);

		pMyListView = new MyListView(this);
		pMyListView->hide();

		//for (int i = 0; i < 10; i++)
		//	pMyListView->insertItem(new MyListViewItem(pMyListView));
		
		connect(pLoginWidget->pPushButtonSignIn, SIGNAL(clicked()), SLOT(clickedSignIn()));

		QVBoxLayout * vlayoutMain = new QVBoxLayout(this, 2, 0);
		vlayoutMain->addWidget(pLoginWidget);
		vlayoutMain->addWidget(pMyListView);

		pClient = new gloox::Client("jabber.te.ua");
		//pClient = new gloox::Client("gmail.com");
		pClient->setResource("QTalk");
		pClient->registerMessageHandler(this);
		pClient->registerConnectionListener(this);
		pClient->rosterManager()->registerRosterListener(this);
	}

	QSettings & settings() { return m_settings; }


	~MainWidget()
	{
		qDebug("~MainWidget()");
	}

	//QThread implementation
	virtual void run()
	{
		//pClient->setUsername(QString("%1@gmail.com").arg(pLoginWidget->username()));
		pClient->setUsername(pLoginWidget->username());
		pClient->setPassword(pLoginWidget->password());
		pLoginWidget->enableControls(false);
		m_usersettings = new gloox::UserSettingsIq(pClient);
		pClient->connect();
		delete m_usersettings;		
		qDebug("run() finished");
	}

	//gloox::MessageHandler implementation
	virtual void handleMessage(gloox::Stanza* stanza, gloox::MessageSession * /*session = 0*/)
	{
		gloox::Stanza *s = gloox::Stanza::createMessageStanza(stanza->from().full(), "hello world");
		pClient->send( s );
		pClient->disconnect();
	}
	
	//gloox::UserSettingHandler implementation
	virtual void handleUserSettings()
	{
	    qDebug("handleUserSettings()");	
	}

	//gloox::ConnectionListener implementation
	virtual void onConnect()
	{	
		qDebug("onConnect()");
		pLoginWidget->enableControls();
		pLoginWidget->hide();
		pMyListView->show();

		m_settings.writeEntry("/username", pLoginWidget->username());
		bool bRemember = pLoginWidget->remember();		
		m_settings.writeEntry("/remember", bRemember);	
		m_settings.writeEntry("/password", bRemember ? pLoginWidget->password() : "");

		
		m_usersettings->fetchUserSetting(this);		
	}

	virtual void onDisconnect(gloox::ConnectionError e)
	{
		qDebug("onDisconnect()");
		qDebug(QString("message_test: disconnected: %1").arg(e));
		if (e == gloox::ConnAuthenticationFailed)
			qDebug(QString("auth failed. reason: %1").arg(pClient->authError()));

		pMyListView->hide();
		pLoginWidget->show();
		pLoginWidget->enableControls();
	}

	virtual bool onTLSConnect(const gloox::CertInfo& info)
	{
		qDebug("onTLSConnect()");
		qDebug(QString("status: %1\nissuer: %2\npeer: %3\nprotocol: %4\nmac: %5\ncipher: %6\ncompression: %7")
			.arg(info.status)
			.arg(info.issuer)
			.arg(info.server)
			.arg(info.protocol)
			.arg(info.mac)
			.arg(info.cipher)
			.arg(info.compression));

		return true;
	}

	//gloox::RosterListener implementation
	virtual void handleItemAdded(const gloox::JID& jid)
	{
		qDebug(QString("added %1").arg(jid.bare()));
	}

	virtual void handleItemSubscribed(const gloox::JID& jid)
	{
		qDebug(QString("subscribed %1").arg(jid.bare()));
	}

	virtual void handleItemRemoved(const gloox::JID& jid)
	{
		qDebug(QString("removed %1").arg(jid.bare()));
	}

	virtual void handleItemUpdated(const gloox::JID& jid )
	{
		qDebug(QString("updated %1").arg(jid.bare()));
	}

	virtual void handleItemUnsubscribed(const gloox::JID& jid)
	{
		qDebug(QString("unsubscribed %1").arg(jid.bare()));
	}

	virtual void handleRoster(const gloox::Roster& roster)
	{
		qDebug("roster arriving\nitems:");

		pMyListView->clear();

		gloox::Roster::const_iterator it = roster.begin();
		for (; it != roster.end(); ++it)
		{
			/*
			qDebug(QString("jid: %1, name: %2, subscription: %3")
				.arg((*it).second->jid())
				.arg((*it).second->name())
				.arg((*it).second->subscription()));
				*/

			MyListViewItem * pMyListViewItem = new MyListViewItem(pMyListView);
			pMyListViewItem->setText(0, QString::fromUtf8((*it).second->name().empty() ? (*it).second->jid().c_str() : (*it).second->name().c_str()));
			pMyListView->insertItem(pMyListViewItem);

			gloox::StringList g = (*it).second->groups();
			gloox::StringList::const_iterator it_g = g.begin();
			/*
			for (; it_g != g.end(); ++it_g)
				qDebug(QString("\tgroup: %1").arg(*it_g));
				*/

			gloox::RosterItem::ResourceMap::const_iterator rit = (*it).second->resources().begin();
			/*
			for (; rit != (*it).second->resources().end(); ++rit)
				qDebug(QString("resource: %1").arg((*rit).first));
				*/
		}
	}

	virtual void handleRosterPresence(const gloox::RosterItem& item, const std::string& resource,
		gloox::Presence presence, const std::string& /*msg*/)
	{
	/*
		qDebug(QString("presence received: %1/%2 -- %3")
			.arg(item.jid())
			.arg(resource)
			.arg(presence));*/
	}

	virtual void handleSelfPresence(const gloox::RosterItem& item, const std::string& resource,
		gloox::Presence presence, const std::string& /*msg*/)
	{
		qDebug(QString("self presence received: %1/%2 -- %3")
			.arg(item.jid())
			.arg(resource)
			.arg(presence));
	}

	virtual bool handleSubscriptionRequest(const gloox::JID& jid, const std::string& /*msg*/)
	{
		qDebug(QString("subscription: %1").arg(jid.bare()));
		gloox::StringList groups;
		gloox::JID id(jid);
		pClient->rosterManager()->subscribe(id, "", groups, "");
		return true;
	}

	virtual bool handleUnsubscriptionRequest(const gloox::JID& jid, const std::string& /*msg*/)
	{
		qDebug(QString("unsubscription: %1").arg(jid.bare()));
		return true;
	}

	virtual void handleNonrosterPresence(gloox::Stanza* stanza)
	{
		qDebug(QString("received presence from entity not in the roster: %1").arg(stanza->from().full()));
	}

	virtual void handleRosterError(gloox::Stanza * /*stanza*/)
	{
		qDebug("an roster-related error occured");
	}



public:
	LoginWidget * pLoginWidget;
	MyListView * pMyListView;
	gloox::UserSettingsIq * m_usersettings;

public slots:
	void clickedSignIn()
	{
		qDebug("clickedSignIn()");
		pClient->setPresence(gloox::PresenceAvailable, 5);
		start();
	}
};
